package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.security.cert.X509Certificate;

public class OJDSServer extends Thread {
	private ServerSocket serverSocket;

	public OJDSServer(ServerSocket serverSocket) {
		this.serverSocket = serverSocket;
		newListener();
	}

	public void run() {
		SSLSocket socket = null;
		try {
			socket = (SSLSocket) serverSocket.accept();
			socket.setNeedClientAuth(true);
		} catch (IOException e) {
			e.printStackTrace();
		}
		newListener();
		SSLSession session = socket.getSession();
		X509Certificate cert = null;
		try {
			cert = (X509Certificate) session.getPeerCertificateChain()[0];
		} catch (SSLPeerUnverifiedException e) {
			e.printStackTrace();
		}
		String subject = cert.getSubjectDN().getName();
		// CN=doctorA, OU=A, O=doctor
		String ID = subject.substring(3, subject.indexOf(","));

		String part2 = subject.substring(subject.indexOf(",") + 1);
		String division = part2.substring(part2.indexOf("=") + 1, part2
				.indexOf(","));
		String part3 = part2.substring(part2.indexOf(",") + 1);
		String occupation = part3.substring(part3.indexOf("=") + 1);
		OutputStream output = null;
		InputStream input = null;
		try {
			output = socket.getOutputStream();
			input = socket.getInputStream();
		} catch (IOException e) {
			e.printStackTrace();
		}
		int action = 0;
		while (true) {
			try {
				action = input.read();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (action == Commands.LOAD) {
				String s = reciveData(input);
				s = ("Journaler/" + s.substring(0, (s.length() / 2) - 1))
						.trim();
				boolean access = loadCheck(s, ID, division, occupation);
				log(s, ID, action, access);
				if (access) {
					sendFile(s, output);
				} else {
					try {
						output.write(Commands.ACCESSDENIED);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			} else if (action == Commands.SAVE) {
				String recieved = reciveData(input);
				recieved = recieved.substring(0, (recieved.length() / 2) - 1);
				String fileName = ("Journaler/" + recieved.substring(0,
						recieved.indexOf("\n"))).trim();
				boolean access = saveCheck(recieved, ID, division, occupation);
				log(fileName, ID, action, access);
				if (access) {
					saveFile(fileName, recieved.substring(recieved
							.indexOf("\n") + 1, recieved.length()));
					try {
						output.write(Commands.SAVESUCCESFUL);
					} catch (IOException e) {
						e.printStackTrace();
					}
				} else {
					try {
						output.write(Commands.ACCESSDENIED);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			} else if (action == Commands.EXIT) {
				break;
			} else if (action == Commands.DELETE) {
				String s = reciveData(input);
				String fileName = ("Journaler/" + s.substring(0,
						(s.length() / 2) - 1)).trim();
				boolean access = deleteCheck(ID, division, occupation);
				log(fileName, ID, action, access);
				if (access) {
					File f = new File(fileName);
					if (!f.exists()) {
						try {
							output.write(Commands.FILENOTFOUND);
						} catch (IOException e) {
							e.printStackTrace();
						}
					} else {
						f.delete();
						try {
							output.write(Commands.DELETESUCCESFUL);
						} catch (IOException e) {
							e.printStackTrace();
						}
					}

				} else {
					try {
						output.write(Commands.ACCESSDENIED);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	private boolean deleteCheck(String name, String division, String occupation) {
		if (name.equals("goverment") && division.equals("S")
				&& occupation.equals("gov")) {
			return true;
		} else {
			return false;
		}
	}

	private boolean saveCheck(String recieved, String ID, String division,
			String occupation) {
		String fileName = ("Journaler/" + recieved.substring(0, recieved
				.indexOf("\n"))).trim();
		File f = new File(fileName);
		boolean exists = f.exists();
		saveFile("temp.ojds", recieved.substring(recieved.indexOf("\n") + 1,
				recieved.length()));
		String things[] = extractFromFile("temp.ojds");
		if (things == null) {
			return false;
		}
		f = new File("temp.ojds");
		f.delete();
		if (things[2].equals(ID) || (things[3].equals(ID) && exists)) {
			return true;
		}
		return false;
	}

	private boolean loadCheck(String fileName, String ID, String division,
			String occupation) {
		String things[] = extractFromFile(fileName);
		if (things == null) {
			return false;
		}
		if (things[0].equals(ID) || things[1].equals(division)
				|| things[2].equals(ID) || things[3].equals(ID)
				|| division.equals("S")) {
			return true;
		}
		return false;
	}

	private String reciveData(InputStream input) {
		byte[] byteArray = new byte[100000];
		while (true) {
			try {
				input.read(byteArray);
				return new String(byteArray);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void newListener() {
		(new Thread(this)).start();
	}

	private void saveFile(String file, String string) {
		File f = new File(file);
		BufferedWriter bf = null;
		try {
			bf = new BufferedWriter(new FileWriter(f));
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			bf.write(string);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void sendFile(String s, OutputStream os) {
		File f = new File(s);
		StringBuilder sb = new StringBuilder();
		sb.append(s + "\n");
		try {
			BufferedReader bf = new BufferedReader(new FileReader(f));
			try {
				while (bf.ready()) {
					sb.append(bf.readLine());
					sb.append("\n");
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				os.write(Commands.FILEFOUND);
				os.write(sb.toString().getBytes());
			} catch (IOException e) {
				e.printStackTrace();
			}
		} catch (FileNotFoundException e) {
			try {
				os.write(Commands.FILENOTFOUND);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}

	private String[] extractFromFile(String s) {
		File f = new File(s);
		BufferedReader bf;
		String patient = null;
		String doctor = null;
		String nurse = null;
		String division = null;
		try {
			bf = new BufferedReader(new FileReader(f));

			if (bf.ready()) {
				patient = bf.readLine();
				if (!patient.substring(0, 8).equals("Patient:")) {
					return null;
				}
				patient = patient.substring(patient.indexOf(":") + 2);
				division = bf.readLine();
				if (!division.substring(0, 9).equals("Division:")) {
					return null;
				}
				division = division.substring(division.indexOf(":") + 2);
				doctor = bf.readLine();
				if (!doctor.substring(0, 7).equals("Doctor:")) {
					return null;
				}
				doctor = doctor.substring(doctor.indexOf(":") + 2);
				nurse = bf.readLine();
				if (!nurse.substring(0, 6).equals("Nurse:")) {
					return null;
				}
				nurse = nurse.substring(nurse.indexOf(":") + 2);
			}
		} catch (FileNotFoundException e) {
		} catch (IOException e) {
		}
		String[] retur = new String[4];
		retur[0] = patient;
		retur[1] = division;
		retur[2] = doctor;
		retur[3] = nurse;
		return retur;
	}
	
	
	private void log(String file, String ID, int action, boolean access){
		long time = System.currentTimeMillis();
		try {
			FileOutputStream f = new FileOutputStream("Journaler/log", true);
			f.write((time + ": "+ ID + " " + action + " " + file + " " + access + "\n").getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}